package cn.good.yan.k3;

import cn.good.yan.k2.t1.Uo;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * k3. stream 流
 *
 * @author shengren.yan
 * @create 2023-08-03
 */
public class Test {

    List<Uo> employeeList = Arrays.asList(
            new Uo("张三",18),
            new Uo("李四",58),
            new Uo("王五",26),
            new Uo("赵六",36),
            new Uo("田七",12),
            new Uo("田七",12)
    );

    public static void main(String[] args) {
        // 1. 创建流
        new ArrayList<>().stream();           // 串行流
        new ArrayList<>().parallelStream();   // 并行流

        // Stream API 可以声明性地通过 parallel（） 与 sequential（） 在并行流与顺序流之间进行切换。
        long reduce = LongStream.rangeClosed(0, 1000000L)
                .parallel()
                .reduce(0, Long::sum);

        //2.通过 Arrays 中的静态方法stream()获取数组流
        Uo[] emps=new Uo[5];
        Stream<Uo> stream2= Arrays.stream(emps);

        //3.通过Stream 类中的静态方法of()
        Stream<String> stream3=Stream.of("a","b","c");

        //4.创建无限流
        //迭代
        Stream<Integer> stream4=Stream.iterate(0, (x) -> x+2);
        stream4.limit(10).forEach(System.out::println);
    }

    /**
     * 筛选与切片
     * 映射
     * 排序
     */
    public void t1() {
        /*  筛选与切片
         *  filter--接收Lambda，从流中排除某些元素。
         *  limit--截断流，使其元素不超过给定数量。
         *  skip(n)--跳过元素，返回一个扔掉了前n个元素的流。若流中元素不足n个，则返回一个空流。与limit(n) 互补
         *  distinct--筛选，通过流所生成元素的 hashCode() 和 equals() 去掉重复元素
         */
        Stream<Uo> stream = employeeList.stream()
                .filter((e) -> e.getAge()>35 )
                .limit(2)
                .skip(2)
                .distinct(); //去重，注意：需要Employee重写hashCode 和 equals 方法

        // 映射
        //  map--接收Lambda，将元素转换成其他形式或提取信息。接收一个函数作为参数，
        //  该函数会被应用到每个元素上，并将其映射成一个新元素。
        //  flatMap--接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流
        List<String> list = Arrays.asList("aaa","bbb","ccc","ddd");
        list.stream().map((str)->str.toUpperCase())
                .forEach(System.out::println);
        employeeList.stream().map(Uo::getUsername);

        // map和flatMap的关系  类似于 add(Object)和addAll(Collection coll)

        // 排序
        employeeList.stream()
                .sorted((e1,e2)->{
                    if(e1.getAge().equals(e2.getAge())){
                        return e1.getUsername().compareTo(e2.getUsername());
                    }else{
                        return e1.getAge().compareTo(e2.getAge());
                    }
                }).forEach(System.out::println);
    }

    /**
     * 查找与匹配
     *  allMatch-----检查是否匹配所有元素
     *  anyMatch-----检查是否至少匹配一个元素
     *  noneMatch----检查是否没有匹配所有元素
     *  findFirst----返回第一个元素
     *  findAny------返回当前流中的任意元素
     *  count--------返回流中元素的总个数
     *  max----------返回流中最大值
     *  min----------返回流中最小值
     */
    public void t2() {
        //allMatch-检查是否匹配所有元素
        boolean b1 = employeeList.stream()
                .allMatch((e)-> e.getUsername().equals("张飞"));
        System.out.println(b1); //false

        //anyMatch-检查是否至少匹配一个元素
        boolean b2 = employeeList.stream()
                .anyMatch((e)-> e.getUsername().equals("张飞"));
        System.out.println(b2);//true
        // 以下的同理...

        //findFirst-返回第一个元素
        Optional<Uo> op = employeeList.stream()
                .sorted((e1,e2)->Double.compare(e1.getAge(), e2.getAge()))
                .findFirst();
        System.out.println(op.get()); //Employee 返回第一个对象

        //findAny-返回当前流中的任意元素  注意是并行流
        Optional<Uo> op2 = employeeList.parallelStream()
                .findAny();

        //count-返回流中元素的总个数
        Long count=employeeList.stream().count();

        //max-返回流中最大值
        Optional<Uo> op3=employeeList.stream()
                .max((e1,e2)->Integer.compare(e1.getAge(), e2.getAge()));
        System.out.println(op3.get()); //返回最大的对象

        //min-最小的同理
        Optional<Integer> op4=employeeList.stream()
                .map(Uo::getAge)
                .min(Integer::compare); //返回最小的值

        // 归约
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y); //0为起始值

        // 计算全部年龄总和
        Integer sum2 = employeeList.stream()
                .map(Uo::getAge)
                .reduce(10, (x, y) -> x + y);   //10为起始值
//                .reduce(10, Integer::sum);             //10为起始值  简写
    }

    /**
     * 收集  分组 分区 连接字符串
     * collect-将流转换为其他形式，接收一个Collector接口的实现，用于给Stream中元素做汇总的方法。
     */
    public void t3() {
        //流转List
        List<String> list = employeeList.stream()
                .map(Uo::getUsername).collect(Collectors.toList());
        //转Set
        Set<Uo> set = employeeList.stream().collect(Collectors.toSet());
        //转HashSet
        HashSet<Uo> hs = employeeList.stream()
                .collect(Collectors.toCollection(HashSet::new));

        //总和
        Long count=employeeList.stream()
                .collect(Collectors.counting());
        //平均值
        Double avg=employeeList.stream()
                .collect(Collectors.averagingDouble(Uo::getAge));

        //总和
        Double sum=employeeList.stream()
                .collect(Collectors.summingDouble(Uo::getAge));

        //最大值
        Optional<Uo> max=employeeList.stream()
                .collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getAge(), e2.getAge())));
        System.out.println(max.get());

        //最小值
        Optional<Integer> min=employeeList.stream()
                .map(Uo::getAge)
                .collect(Collectors.minBy(Integer::compare));
        //分组
        Map<Integer, List<Uo>> collect = employeeList.stream().collect(Collectors.groupingBy(Uo::getAge));
        System.out.println(collect);

        //多级分组
        Map<String, Map<String, List<Uo>>> collect1 = employeeList.stream()
                .collect(
                        Collectors.groupingBy(
                                Uo::getUsername,
                                Collectors.groupingBy(
                                        (e) -> {
                                            if (e.getAge() <= 35) {
                                                return "青年";
                                            } else if (e.getAge() <= 50) {
                                                return "中年";
                                            } else {
                                                return "老年";
                                            }
                                        })
                        )
                );
        //分区--- 分成两组（满足条件和不满足条件）
        Map<Boolean,List<Uo>> map3 = employeeList.stream()
                .collect(Collectors.partitioningBy((e)->e.getAge()>8000));

        //收集平均值、最大值、总和...
        DoubleSummaryStatistics dss=employeeList.stream()
                .collect(Collectors.summarizingDouble(Uo::getAge));
        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());

        //连接字符串
        String strr= employeeList.stream()
                .map(Uo::getUsername)
                .collect(Collectors.joining(","));

    }

}
